﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;

namespace Xceed.Silverlight.Data
{
  internal class ItemPositionConverterEnumerator<T> : AsyncParentEnumerator<T> where T : RawDataItem
  {
    #region Constructor

    internal ItemPositionConverterEnumerator(
      IAsyncEnumerator childEnumerator,
      IContextualItemHelper<T> itemHelper )
      : base( childEnumerator )
    {
      if( itemHelper == null )
        throw new ArgumentNullException( "itemHelper" );

      m_itemHelper = itemHelper;
    }

    #endregion

    public override JumpMoveAndFetchAsyncResult BeginJumpMoveAndFetch(
      JumpMoveAndFetchParameters parameters,
      AsyncCallback callback,
      object state )
    {
      this.CheckMoveAndFetchParameters( parameters.ExpectedMoveCount, parameters.ExpectedFetchCount );

      ItemPosition itemPosition = parameters.SourcePosition as ItemPosition;

      // Convert the ItemPosition into a SortPosition.
      if( ( itemPosition != null ) && ( this.Convert( itemPosition ) ) )
      {
        T item = itemPosition.Item as T;

        if( item == null )
          throw new ArgumentException( "The specified ItemPosition must be a RawDataItem instance.", "parameters" );

        // Find out if the cursor must be placed before or after the item.
        long moveCount = parameters.ExpectedMoveCount;
        int fetchCount = parameters.ExpectedFetchCount;
        bool isHeadingForward = DataUtils.IsQueryingForward( moveCount, fetchCount );
        StartPosition startPosition;

        // The item that is at the ItemPosition must be returned if its available.
        if( moveCount == 0 )
        {
          startPosition = ( isHeadingForward )
                            ? StartPosition.Before
                            : StartPosition.After;
        }
        // The item that is at the ItemPosition must be skipped.
        else
        {
          startPosition = ( isHeadingForward )
                            ? StartPosition.After
                            : StartPosition.Before;

          // There is no need to adjust the move count even if we have skipped
          // the item since it takes one move to move the cursor on the next item.
        }

        DataSourceContext context = parameters.Context;

        SortPosition sortPosition = SortPosition.Create(
                                      context,
                                      item,
                                      startPosition,
                                      m_itemHelper );

        // Create the new query parameters to use.
        parameters = new JumpMoveAndFetchParameters(
                       sortPosition,
                       moveCount,
                       fetchCount,
                       parameters.ApproximateMove,
                       context );
      }

      return base.BeginJumpMoveAndFetch( parameters, callback, state );
    }

    protected virtual bool Convert( ItemPosition itemPosition )
    {
      return true;
    }

    #region Private Fields

    private readonly IContextualItemHelper<T> m_itemHelper;

    #endregion
  }
}
